<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="Hexo Theme Redefine">
    
    <meta name="author" content="xiaoeryu">
    <!-- preconnect -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    
    <!--- Seo Part-->
    
    <link rel="canonical" href="https://xiaoeeyu.github.io/2023/09/22/art下抽取壳实现/"/>
    <meta name="robots" content="index,follow">
    <meta name="googlebot" content="index,follow">
    <meta name="revisit-after" content="1 days">
    
    
    
        
        <meta name="description" content="函数抽取壳出现之后基本宣告一代壳整体保护的结束，由此进入到二代壳的时代。 接下来我们来分析一下二代壳的原理，看它在Dalvik&amp;ART下分别是怎么实现函数抽取的，以及如何脱二代壳。">
<meta property="og:type" content="article">
<meta property="og:title" content="ART下抽取壳实现">
<meta property="og:url" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/index.html">
<meta property="og:site_name" content="xiaoeryu">
<meta property="og:description" content="函数抽取壳出现之后基本宣告一代壳整体保护的结束，由此进入到二代壳的时代。 接下来我们来分析一下二代壳的原理，看它在Dalvik&amp;ART下分别是怎么实现函数抽取的，以及如何脱二代壳。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922234409887.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230914213751277.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916000421315.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916004845488.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916012034450.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916012839402.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916092311779.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916102228369.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916105427130.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916120243319.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916151740306.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916152824758.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230921165608812.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230921170635600.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922003852713.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922004358684.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922005501457.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922011727856.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922012756117.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922013053840.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922014246796.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922014735501.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922230604364.png">
<meta property="article:published_time" content="2023-09-22T15:28:32.000Z">
<meta property="article:modified_time" content="2023-09-26T03:34:05.308Z">
<meta property="article:author" content="xiaoeryu">
<meta property="article:tag" content="Android脱壳">
<meta property="article:tag" content="学习笔记">
<meta property="article:tag" content="Android源码分析">
<meta property="article:tag" content="ART脱壳">
<meta property="article:tag" content="函数抽取壳">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://xiaoeeyu.github.io/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922234409887.png">
    
    
    <!--- Icon Part-->
    <link rel="icon" type="image/png" href="/images/rabete.jpg" sizes="192x192">
    <link rel="apple-touch-icon" sizes="180x180" href="/images/rabete.jpg">
    <meta name="theme-color" content="#A31F34">
    <link rel="shortcut icon" href="/images/rabete.jpg">
    <!--- Page Info-->
    
    <title>
        
            ART下抽取壳实现 | xiaoeryu
        
    </title>

    
<link rel="stylesheet" href="/fonts/Chillax/chillax.css">


    <!--- Inject Part-->
    

    
<link rel="stylesheet" href="/css/style.css">


    
        
<link rel="stylesheet" href="/css/build/tailwind.css">

    

    
<link rel="stylesheet" href="/fonts/GeistMono/geist-mono.css">

    
<link rel="stylesheet" href="/fonts/Geist/geist.css">

    <!--- Font Part-->
    
    
    
    
    
    

    <script id="hexo-configurations">
    window.config = {"hostname":"xiaoeeyu.github.io","root":"/","language":"zh-CN","path":"search.xml"};
    window.theme = {"articles":{"style":{"font_size":"16px","line_height":1.5,"image_border_radius":"14px","image_alignment":"center","image_caption":false,"link_icon":true,"delete_mask":false,"title_alignment":"left","headings_top_spacing":{"h1":"3.2rem","h2":"2.4rem","h3":"1.9rem","h4":"1.6rem","h5":"1.4rem","h6":"1.3rem"}},"word_count":{"enable":true,"count":true,"min2read":true},"author_label":{"enable":true,"auto":false,"list":[]},"code_block":{"copy":true,"style":"mac","highlight_theme":{"light":"github","dark":"vs2015"},"font":{"enable":false,"family":null,"url":null}},"toc":{"enable":true,"max_depth":4,"number":false,"expand":true,"init_open":true},"copyright":{"enable":true,"default":"cc_by_nc_sa"},"lazyload":true,"pangu_js":false,"recommendation":{"enable":false,"title":"推荐阅读","limit":3,"mobile_limit":2,"placeholder":"/images/ball-0101.jpg","skip_dirs":[]}},"colors":{"primary":"#A31F34","secondary":null,"default_mode":"light"},"global":{"fonts":{"chinese":{"enable":false,"family":null,"url":null},"english":{"enable":false,"family":null,"url":null},"title":{"enable":false,"family":null,"url":null}},"content_max_width":"1000px","sidebar_width":"210px","hover":{"shadow":true,"scale":false},"scroll_progress":{"bar":false,"percentage":true},"website_counter":{"url":"https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js","enable":true,"site_pv":true,"site_uv":true,"post_pv":true},"single_page":true,"preloader":{"enable":false,"custom_message":null},"open_graph":true,"google_analytics":{"enable":false,"id":null}},"home_banner":{"enable":true,"style":"fixed","image":{"light":"/images/wallhaven-jxl31y.png","dark":"/images/wallhaven-o5762l.png"},"title":"XIAOERYU","subtitle":{"text":["明心见性，拨云见日","Don't wait, to create"],"hitokoto":{"enable":false,"show_author":false,"api":"https://v1.hitokoto.cn"},"typing_speed":100,"backing_speed":80,"starting_delay":500,"backing_delay":1500,"loop":true,"smart_backspace":true},"text_color":{"light":"#fff","dark":"#d1d1b6"},"text_style":{"title_size":"2.8rem","subtitle_size":"1.5rem","line_height":1.2},"custom_font":{"enable":false,"family":null,"url":null},"social_links":{"enable":true,"style":"default","links":{"github":"https://github.com/xiaoeeyu","instagram":null,"zhihu":null,"twitter":null,"email":"xiaoeryu@163.com"},"qrs":{"weixin":null}}},"plugins":{"feed":{"enable":false},"aplayer":{"enable":false,"type":"fixed","audios":[{"name":null,"artist":null,"url":null,"cover":null,"lrc":null}]},"mermaid":{"enable":false,"version":"9.3.0"}},"version":"2.8.2","navbar":{"auto_hide":false,"color":{"left":"#f78736","right":"#367df7","transparency":35},"width":{"home":"1200px","pages":"1000px"},"links":{"Home":{"path":"/","icon":"fa-regular fa-house"},"Archives":{"path":"/archives","icon":"fa-regular fa-archive"}},"search":{"enable":true,"preload":true}},"page_templates":{"friends_column":2,"tags_style":"blur"},"home":{"sidebar":{"enable":true,"position":"left","first_item":"menu","announcement":null,"show_on_mobile":true,"links":null},"article_date_format":"auto","excerpt_length":200,"categories":{"enable":true,"limit":3},"tags":{"enable":true,"limit":3}},"footerStart":"2022/8/17 11:45:14"};
    window.lang_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 个月前","year":"%s 年前"};
    window.data = {"masonry":false};
  </script>
    
    <!--- Fontawesome Part-->
    
<link rel="stylesheet" href="/fontawesome/fontawesome.min.css">

    
<link rel="stylesheet" href="/fontawesome/brands.min.css">

    
<link rel="stylesheet" href="/fontawesome/solid.min.css">

    
<link rel="stylesheet" href="/fontawesome/regular.min.css">

    
    
    
    
<meta name="generator" content="Hexo 6.3.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>



<body>
	<div class="progress-bar-container">
	

	
	<span class="pjax-progress-bar"></span>
	<!--        <span class="swup-progress-icon">-->
	<!--            <i class="fa-solid fa-circle-notch fa-spin"></i>-->
	<!--        </span>-->
	
</div>

<main class="page-container" id="swup">

	

	<div class="main-content-container flex flex-col justify-between min-h-dvh">
		<div class="main-content-header">
			<header class="navbar-container px-6 md:px-12">
    <div class="navbar-content transition-navbar ">
        <div class="left">
            
                <a class="logo-image h-8 w-8 sm:w-10 sm:h-10 mr-3" href="/">
                    <img src="/images/rabete.jpg" class="w-full h-full rounded-sm">
                </a>
            
            <a class="logo-title" href="/">
                
                xiaoeryu
                
            </a>
        </div>

        <div class="right">
            <!-- PC -->
            <div class="desktop">
                <ul class="navbar-list">
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/"
                                        >
                                    <i class="fa-regular fa-house fa-fw"></i>
                                    首页
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/archives"
                                        >
                                    <i class="fa-regular fa-archive fa-fw"></i>
                                    归档
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                    
                        <li class="navbar-item search search-popup-trigger">
                            <i class="fa-solid fa-magnifying-glass"></i>
                        </li>
                    
                </ul>
            </div>
            <!-- Mobile -->
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fa-solid fa-magnifying-glass"></i>
                    </div>
                
                <div class="icon-item navbar-bar">
                    <div class="navbar-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Mobile sheet -->
    <div class="navbar-drawer h-dvh w-full absolute top-0 left-0 bg-background-color flex flex-col justify-between">
        <ul class="drawer-navbar-list flex flex-col px-4 justify-center items-start">
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/"
                        >
                            <span>
                                首页
                            </span>
                            
                                <i class="fa-regular fa-house fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/archives"
                        >
                            <span>
                                归档
                            </span>
                            
                                <i class="fa-regular fa-archive fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            

            
            
        </ul>

        <div class="statistics flex justify-around my-2.5">
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/tags">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">92</div>
        <div class="label text-third-text-color text-sm">标签</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/categories">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">14</div>
        <div class="label text-third-text-color text-sm">分类</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/archives">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">112</div>
        <div class="label text-third-text-color text-sm">文章</div>
    </a>
</div>
    </div>

    <div class="window-mask"></div>

</header>


		</div>

		<div class="main-content-body transition-fade-up">
			

			<div class="main-content">
				<div class="post-page-container flex relative justify-between box-border w-full h-full">
	<div class="article-content-container">

		<div class="article-title relative w-full">
			
			<div class="w-full flex items-center pt-6 justify-start">
				<h1 class="article-title-regular text-second-text-color tracking-tight text-4xl md:text-6xl font-semibold px-2 sm:px-6 md:px-8 py-3">ART下抽取壳实现</h1>
			</div>
			
		</div>

		
		<div class="article-header flex flex-row gap-2 items-center px-2 sm:px-6 md:px-8">
			<div class="avatar w-[46px] h-[46px] flex-shrink-0 rounded-medium border border-border-color p-[1px]">
				<img src="/images/rabete.jpg">
			</div>
			<div class="info flex flex-col justify-between">
				<div class="author flex items-center">
					<span class="name text-default-text-color text-lg font-semibold">xiaoeryu</span>
					
					<span class="author-label ml-1.5 text-xs px-2 py-0.5 rounded-small text-third-text-color border border-shadow-color-1">Lv5</span>
					
				</div>
				<div class="meta-info">
					<div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fa-regular fa-pen-fancy"></i>&nbsp;
        <span class="desktop">2023-09-22 23:28:32</span>
        <span class="mobile">2023-09-22 23:28:32</span>
        <span class="hover-info">创建</span>
    </span>
    
        <span class="article-date article-meta-item">
            <i class="fa-regular fa-wrench"></i>&nbsp;
            <span class="desktop">2023-09-26 11:34:05</span>
            <span class="mobile">2023-09-26 11:34:05</span>
            <span class="hover-info">更新</span>
        </span>
    

    
        <span class="article-categories article-meta-item">
            <i class="fa-regular fa-folders"></i>&nbsp;
            <ul>
                
                
                    
                        
                        <li>
                            <a href="/categories/Android%E9%80%86%E5%90%91/">Android逆向</a>&nbsp;
                        </li>
                    
                    
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fa-regular fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/Android%E8%84%B1%E5%A3%B3/">Android脱壳</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/Android%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/">Android源码分析</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/ART%E8%84%B1%E5%A3%B3/">ART脱壳</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/%E5%87%BD%E6%95%B0%E6%8A%BD%E5%8F%96%E5%A3%B3/">函数抽取壳</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
    
    
        <span class="article-pv article-meta-item">
            <i class="fa-regular fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

				</div>
			</div>
		</div>
		

		


		<div class="article-content markdown-body px-2 sm:px-6 md:px-8 pb-8">
			<p>函数抽取壳出现之后基本宣告一代壳整体保护的结束，由此进入到二代壳的时代。</p>
<p>接下来我们来分析一下二代壳的原理，看它在Dalvik&amp;ART下分别是怎么实现函数抽取的，以及如何脱二代壳。</p>
<span id="more"></span>

<h1 id="Dalvik下的函数抽取"><a href="#Dalvik下的函数抽取" class="headerlink" title="Dalvik下的函数抽取"></a>Dalvik下的函数抽取</h1><p>关于Dalvik下函数抽取壳的实现可以去看看《Android应用安全防护和逆向分析》的作者-姜维写的两篇文章和书中都有介绍</p>
<p><a class="link" target="_blank" rel="noopener" href="http://www.520monkey.com/archives/1118">Android中实现「类方法指令抽取方式」加固方案原理解析<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<ul>
<li>这篇文章对dex的结构做了一个简单的介绍，怎么去定位函数指令的地址。最后实现了一个函数抽取壳的demo</li>
</ul>
<p><a class="link" target="_blank" rel="noopener" href="http://www.520monkey.com/archives/1115">Android免Root权限通过Hook系统函数修改程序运行时内存指令逻辑<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<ul>
<li>这篇文章是前一篇文章的一个基础</li>
</ul>
<p><strong>这两篇文章介绍了在Dalvik下的函数抽取壳的原理和代码实现，实现函数抽取壳脱壳重要的一点是我们恢复这个函数的时机一定要早于这个函数被调用的时机，如果我们恢复的时机晚于被调用的时机的话那这个app的逻辑就被破坏掉了，APP自然就会崩溃。我们要保证当一个函数被调用，它的指令流必须是已经被修复了，这个就需要我们去分析源码来找到这个合适的时机点</strong></p>
<p>这里先看一下<a class="link" target="_blank" rel="noopener" href="http://www.520monkey.com/archives/1118">Android中实现「类方法指令抽取方式」加固方案原理解析<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>这篇文章当中的时机点是怎么找的</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922234409887.png" class="" title="image-20230922234409887">

<ul>
<li>这篇文章里指令还原选用的是dexFindClass()，我们通过源码来看一下这个函数</li>
</ul>
<blockquote>
<p>我们前面讲过类加载的时候有三个步骤：</p>
<ol>
<li>装载：查找和导入Class文件</li>
<li>链接：其中解析步骤是可以选择的<ol>
<li>链接：其中解析步骤是可以选择的</li>
<li>准备：给类的静态变量分配存储空间</li>
<li>解析：将符号引用转成直接引用</li>
</ol>
</li>
<li>初始化：即调用**<clinit>**函数，对静态变量，静态代码块执行初始化工作</clinit></li>
</ol>
</blockquote>
<p>在这个类加载的过程中是有很多的时机供我们选择的。</p>
<p>先来看一下这个时机点</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230914213751277.png" class="" title="image-20230914213751277">

<p>当dex被加载完之后，就要去加载dex当中的类了：加载的时候又分两种方式。</p>
<blockquote>
<p>类加载的时机：</p>
<ol>
<li><p>隐式加载：</p>
<p>创建类的实例</p>
<p>访问类的静态变量，或者为静态变量赋值</p>
<p>调用类的静态方法</p>
<p>使用反射方式来强制创建某个类或接口对应的java.lang.Class对象</p>
<p>初始化某个类的子类</p>
</li>
<li><p>显示加载：两者又有所区别</p>
<p>使用LoadClass()加载</p>
<p>使用forName()加载</p>
</li>
</ol>
</blockquote>
<h2 id="下面我们先分析一下LoadClass-加载类的流程"><a href="#下面我们先分析一下LoadClass-加载类的流程" class="headerlink" title="下面我们先分析一下LoadClass()加载类的流程"></a>下面我们先分析一下LoadClass()加载类的流程</h2><ol>
<li><p>因为我们是用DexClassLoader加载dex的，所以从DexClassLoader开始进入去找LoadClass()</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916000421315.png" class="" title="image-20230916000421315">
</li>
<li><p>继续往下分析loadClass()</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916004845488.png" class="" title="image-20230916004845488">
</li>
<li><p>跟进去findClass()</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916012034450.png" class="" title="image-20230916012034450">
</li>
<li><p>跟进loadClassBinaryName()</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916012839402.png" class="" title="image-20230916012839402">

<ul>
<li>这里经过了几次调用直接进入了Native层</li>
</ul>
</li>
<li><p>接下来就进入了Native层</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916092311779.png" class="" title="image-20230916092311779">
</li>
<li><p>接下来进入findClassNoInit()</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916102228369.png" class="" title="image-20230916102228369">

<ul>
<li><p>这里的dexFindClass()就是我们前面要找的那个hook点，通过hook这个函数来实现对抽取函数的恢复解决方案。</p>
</li>
<li><p>整个原理等于是hook掉类被加载的时机来实现函数的恢复方案，这个时机肯定是在函数执行之前完成的，因此它也就能够保证APP的正常运行</p>
</li>
<li><p>往下继续分析也能找到其它的hook点，不过再往下可能就没有导出符号了，这个函数是有导出符号的可以直接在libdvm.so的导出函数找到（<code>android-4.4.4_r1/out/target/product/manta/symbols/system/lib/libdvm.so</code>），所以hook起来也容易一些。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916105427130.png" class="" title="image-20230916105427130"></li>
</ul>
<p> <strong>到这里我们基本上搞清楚了这篇文章中Dalvik下函数抽取壳的原理</strong>，接下来我们去分析ART下的函数抽取壳原理</p>
</li>
</ol>
<h1 id="ART下的函数抽取以及修复"><a href="#ART下的函数抽取以及修复" class="headerlink" title="ART下的函数抽取以及修复"></a>ART下的函数抽取以及修复</h1><p>ART下修复dex有两种方案：</p>
<ol>
<li>禁掉dex2oat</li>
<li>在执行dex2oat之前填充修改dex</li>
</ol>
<p>首先看来第一种方案这种方案使用比较普遍，代价是牺牲掉了一部分运行效率，因为oat文件的运行效率要比dex文件高。但是，如果用第二种方案在dex2oat的过程中dex文件是完整的，很容易在编译流程中被完整的脱下来。</p>
<h2 id="禁用掉dex2oat的编译流程"><a href="#禁用掉dex2oat的编译流程" class="headerlink" title="禁用掉dex2oat的编译流程"></a>禁用掉dex2oat的编译流程</h2><p>再来看一下art下dexClassLoader()的加载，<strong>还是分析Android8.0的DexClassLoader流程</strong>，前面的流程在上一章分析过了，直接搜索GenerateOatFileNoChecks<em>（DexClassLoader加载dex的流程最终会进入到这里）</em>。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916120243319.png" class="" title="image-20230916120243319">

<ol>
<li><p>进来之后往下找找能看到Dex2Oat()</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916151740306.png" class="" title="image-20230916151740306">
</li>
<li><p>继续跟踪</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230916152824758.png" class="" title="image-20230916152824758"></li>
</ol>
<ul>
<li>上面这些流程就是最终用来调用dex2oat的流程，打断这个流程即可终止对dex2oat二进制程序的调用</li>
</ul>
<h3 id="HOOK-execve"><a href="#HOOK-execve" class="headerlink" title="HOOK execve()"></a>HOOK execve()</h3><p><strong>接下来通过HOOK libc库中的execve()来打断对dex2oat的调用</strong></p>
<p>github上有类似的项目不过好多年没有更新了，对有些art版本可能已经不适用了<a class="link" target="_blank" rel="noopener" href="https://github.com/asLody/TurboDex/tree/master">链接<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<p>hook代码：</p>
<pre><code class="C++">void hooklibc() {
    LOGD("go into hooklibc");
    //7.0 命名空间限制
    void *libc_addr = dlopen_compat("libc.so", RTLD_NOW);
    void *execve_addr = dlsym_compat(libc_addr, "execve");
    if (execve_addr != NULL) {
        if (ELE7EN_OK == registerInlineHook((uint32_t) execve_addr, (uint32_t) myexecve,
                                            (uint32_t **) &amp;oriexecve)) {
            if (ELE7EN_OK == inlineHook((uint32_t) execve_addr)) {
                LOGD("inlineHook execve success");
            } else {
                LOGD("inlineHook execve failure");
            }
        }
    }
}
</code></pre>
<p>还要重写execve的代码：让它判断一下如果是dex2oat调用的时候直接返回，如果不是也不影响它原来的流程</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230921165608812.png" class="" title="image-20230921165608812">

<pre><code class="C++">void* *myexecve(const char *__file, char *const *__argv, char *const *__envp) {
    LOGD("process:%d,enter execve:%s", getpid(), __file);
    if (strstr(__file, "dex2oat")) {
        return NULL;
    } else {
        return oriexecve(__file, __argv, __envp);
    }
}
</code></pre>
<ul>
<li>这样就可以停止它dex2oat的流程，接下来要找到一个时机点去还原被抽空的函数</li>
</ul>
<p><a class="link" target="_blank" rel="noopener" href="https://bbs.kanxue.com/thread-254028.htm">参考寒冰的这篇文章<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230921170635600.png" class="" title="image-20230921170635600">

<p><strong>这里手动修改dex抽取一个函数试一下，看一下函数抽取的流程</strong></p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922003852713.png" class="" title="image-20230922003852713">

<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922004358684.png" class="" title="image-20230922004358684">

<ul>
<li><p>首先要从这些类列表中找到我们要修改抽取的函数，我们可以看到这里面有一千多个类太多了，可以把它的结构导出搜索一下它的位置</p>
</li>
<li><p>找到之后我们来看一下dex文件格式的结构图，看函数抽取需要修改哪些内容</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922005501457.png" class="" title="image-20230922005501457">

<ul>
<li><p>函数抽取的关键就在于对codeItem部分进行修改</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922011727856.png" class="" title="image-20230922011727856">

<ul>
<li>这是它字节对应的结构，前16个字节对应它代表的结构信息，后面16个字节代表对应的代码指令</li>
</ul>
<p>这样寻找是为了去理解文件的结构，找起来比较麻烦，简单的办法是直接用jda打开函数用16禁止查看</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922012756117.png" class="" title="image-20230922012756117">

<ul>
<li>定位到之后在010Editor里面按<strong>ctrl+G</strong>搜索这个地址即可</li>
</ul>
<p><strong>接下来我们如果要对函数进行抽空就需要对它的代码指令部分（后16个字节）进行清零</strong></p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922013053840.png" class="" title="image-20230922013053840">

<p>代码指令部分修改完成之后还要重新计算校验和修改dex里面的checksum</p>
<ul>
<li><p>计算校验和脚本</p>
<pre><code class="python">#! /usr/bin/python
# -*- coding: utf8 -*-
import binascii  #删除缩进(Tab)

def CalculationVar(srcByte,vara,varb):#删除缩进(Tab)
    varA = vara
    varB = varb
    icount = 0
    listAB = []

    while icount &lt; len(srcByte):
        varA = (varA + srcByte[icount]) % 65521
        varB = (varB + varA) % 65521
        icount += 1

    listAB.append(varA)
    listAB.append(varB)

    return listAB

def getCheckSum(varA,varB): #删除缩进(Tab)
    Output = (varB &lt;&lt; 16) + varA
    return Output

if __name__ == '__main__':
    filename = '4_chouqu.dex'				# 计算校验和的文件
    f = open(filename, 'rb', True)
    f.seek(0x0c)
    VarA = 1
    VarB = 0
    flag = 0
    CheckSum = 0
    while True:
        srcBytes = []
        for i in range(1024):               #一次只读1024个字节，防止内存占用过大
            ch = f.read(1)
            if not ch:                      #如果读取到末尾，设置标识符，然后退出读取循环
                flag = 1
                break
            else:
                ch = binascii.b2a_hex(ch)              #将字节转为int类型，然后添加到数组中
                ch = str(ch)
                ch = int(ch,16)
                srcBytes.append(ch)
        varList = CalculationVar(srcBytes,VarA,VarB)
        VarA = varList[0]
        VarB = varList[1]
        if flag == 1:
            CheckSum = getCheckSum(VarA,VarB)
            break
    print('[*] DEX FILENAME: '+filename)
    print('[+] CheckSum = '+hex(CheckSum))
</code></pre>
</li>
</ul>
<p>用计算的校验和替换掉原来的校验和</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922014246796.png" class="" title="image-20230922014246796"></li>
</ul>
<p><strong>修改完成我们打开修改过后的dex查看这个函数抽取效果</strong></p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922014735501.png" class="" title="image-20230922014735501">

<ul>
<li>这里就可以看到它已经抽空成功，函数体原来的代码已经变为了nop</li>
</ul>
</li>
</ul>
<h3 id="还原函数抽取"><a href="#还原函数抽取" class="headerlink" title="还原函数抽取"></a>还原函数抽取</h3><p>在这里还原这个函数需要用到dex文件的method列表结构，去定位到testFunc()这个函数的位置，在它初始化的时候把它原来的字节填充回去</p>
<img lazyload="" src="/images/loading.svg" data-src="/2023/09/22/ART%E4%B8%8B%E6%8A%BD%E5%8F%96%E5%A3%B3%E5%AE%9E%E7%8E%B0/image-20230922230604364.png" class="" title="image-20230922230604364">

<pre><code class="c++">if (artmethod-&gt;dex_method_index_ == 15203) {//TestClass.testFunc-&gt;methodidx
    LOGD("process:%d,enter loadmethod:dexfilebegin:%p,size:%d,start repire method", getpid(),
         dexfile-&gt;begin, dexfile-&gt;size);
    byte *code_item_addr = (byte *) dexfile-&gt;begin + artmethod-&gt;dex_code_item_offset_;
    LOGD("process:%d,enter loadmethod:dexfilebegin:%p,size:%d,beforedumpcodeitem:%p", getpid(),
         dexfile-&gt;begin, dexfile-&gt;size, code_item_addr);

    int result = mprotect(dexfile-&gt;begin, dexfile-&gt;size, PROT_WRITE);
    byte *code_item_start = static_cast&lt;byte *&gt;(code_item_addr) + 16;
    LOGD("process:%d,enter loadmethod:dexfilebegin:%p,size:%d,code_item_start:%p", getpid(),
         dexfile-&gt;begin, dexfile-&gt;size, code_item_start);
    byte inst[16] = {0x1a, 0x00, 0xed, 0x34, 0x1a, 0x01, 0x43, 0x32, 0x71, 0x20, 0x91, 0x05,
                     0x10, 0x00, 0x0e, 0x00};
    for (int i = 0; i &lt; sizeof(inst); i++) {
        code_item_start[i] = inst[i];
    }
    // 可以修改指向的字符串
    code_item_start[2] = 0x43;
    code_item_start[3] = 0x23;
    memset(dexfilepath, 0, 100);
    sprintf(dexfilepath, "/sdcard/%d_%d.dex_15203_2", dexfile-&gt;size, getpid());
    fd = open(dexfilepath, O_CREAT | O_RDWR, 0666);
    if (fd &gt; 0) {
        write(fd, dexfile-&gt;begin, dexfile-&gt;size);
        close(fd);
    }
}
</code></pre>
<p>在获取结构体字段位置的时候，可以不用解析dex文件结构的方式（这样做代码量会比较大，我们也不需要那么多字段），定义一下我们需要的结构体字段直接使用也可以</p>
<pre><code class="c++">struct DexFile {
    // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
    // The class we are a part of.
    uint32_t declaring_class_;
    // Access flags; low 16 bits are defined by spec.
    void *begin;
    /* Dex file fields. The defining dex file is available via declaring_class_-&gt;dex_cache_ */
    // Offset to the CodeItem.
    uint32_t size;
};
struct ArtMethod {
    // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
    // The class we are a part of.
    uint32_t declaring_class_;
    // Access flags; low 16 bits are defined by spec.
    uint32_t access_flags_;
    /* Dex file fields. The defining dex file is available via declaring_class_-&gt;dex_cache_ */
    // Offset to the CodeItem.
    uint32_t dex_code_item_offset_;
    // Index into method_ids of the dex file associated with this method.
    uint32_t dex_method_index_;
};
</code></pre>

		</div>

		
		<div class="post-copyright-info w-full my-8 px-2 sm:px-6 md:px-8">
			<div class="article-copyright-info-container">
    <ul>
        <li><strong>标题:</strong> ART下抽取壳实现</li>
        <li><strong>作者:</strong> xiaoeryu</li>
        <li><strong>创建于
                :</strong> 2023-09-22 23:28:32</li>
        
            <li>
                <strong>更新于
                    :</strong> 2023-09-26 11:34:05
            </li>
        
        <li>
            <strong>链接:</strong> https://github.com/xiaoeryu/2023/09/22/ART下抽取壳实现/
        </li>
        <li>
            <strong>
                版权声明:
            </strong>
            

            
                本文章采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0">CC BY-NC-SA 4.0</a> 进行许可。
            
        </li>
    </ul>
</div>

		</div>
		

		
		<ul class="post-tags-box text-lg mt-1.5 flex-wrap justify-center flex md:hidden">
			
			<li class="tag-item mx-0.5">
				<a href="/tags/Android%E8%84%B1%E5%A3%B3/">#Android脱壳</a>&nbsp;
			</li>
			
			<li class="tag-item mx-0.5">
				<a href="/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">#学习笔记</a>&nbsp;
			</li>
			
			<li class="tag-item mx-0.5">
				<a href="/tags/Android%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/">#Android源码分析</a>&nbsp;
			</li>
			
			<li class="tag-item mx-0.5">
				<a href="/tags/ART%E8%84%B1%E5%A3%B3/">#ART脱壳</a>&nbsp;
			</li>
			
			<li class="tag-item mx-0.5">
				<a href="/tags/%E5%87%BD%E6%95%B0%E6%8A%BD%E5%8F%96%E5%A3%B3/">#函数抽取壳</a>&nbsp;
			</li>
			
		</ul>
		

		

		
		<div class="article-nav my-8 flex justify-between items-center px-2 sm:px-6 md:px-8">
			
			<div class="article-prev border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="prev" rel="prev" href="/2023/09/26/FART%E4%B8%AD%E7%9A%84%E8%84%B1%E5%A3%B3%E7%82%B9-%E8%84%B1%E5%A3%B3%E7%BB%84%E4%BB%B6/">
					<span class="left arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-left"></i>
					</span>
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">FART中的脱壳点-脱壳组件</span>
						<span class="post-nav-item">上一篇</span>
					</span>
				</a>
			</div>
			
			
			<div class="article-next border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="next" rel="next" href="/2023/09/14/ART%E4%B8%8B%E4%B8%80%E4%BB%A3%E5%A3%B3%E9%80%9A%E7%94%A8%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/">
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">ART下一代壳通用解决方案</span>
						<span class="post-nav-item">下一篇</span>
					</span>
					<span class="right arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-right"></i>
					</span>
				</a>
			</div>
			
		</div>
		


		
		<div class="comment-container px-2 sm:px-6 md:px-8 pb-8">
			<div class="comments-container mt-10 w-full ">
    <div id="comment-anchor" class="w-full h-2.5"></div>
    <div class="comment-area-title w-full my-1.5 md:my-2.5 text-xl md:text-3xl font-bold">
        评论
    </div>
    

        
            


        
    
</div>

		</div>
		
	</div>

	
	<div class="toc-content-container">
		<div class="post-toc-wrap">
	<div class="post-toc">
		<div class="toc-title">目录</div>
		<div class="page-title">ART下抽取壳实现</div>
		<ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Dalvik%E4%B8%8B%E7%9A%84%E5%87%BD%E6%95%B0%E6%8A%BD%E5%8F%96"><span class="nav-text">Dalvik下的函数抽取</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%8B%E9%9D%A2%E6%88%91%E4%BB%AC%E5%85%88%E5%88%86%E6%9E%90%E4%B8%80%E4%B8%8BLoadClass-%E5%8A%A0%E8%BD%BD%E7%B1%BB%E7%9A%84%E6%B5%81%E7%A8%8B"><span class="nav-text">下面我们先分析一下LoadClass()加载类的流程</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#ART%E4%B8%8B%E7%9A%84%E5%87%BD%E6%95%B0%E6%8A%BD%E5%8F%96%E4%BB%A5%E5%8F%8A%E4%BF%AE%E5%A4%8D"><span class="nav-text">ART下的函数抽取以及修复</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%A6%81%E7%94%A8%E6%8E%89dex2oat%E7%9A%84%E7%BC%96%E8%AF%91%E6%B5%81%E7%A8%8B"><span class="nav-text">禁用掉dex2oat的编译流程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#HOOK-execve"><span class="nav-text">HOOK execve()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%BF%98%E5%8E%9F%E5%87%BD%E6%95%B0%E6%8A%BD%E5%8F%96"><span class="nav-text">还原函数抽取</span></a></li></ol></li></ol></li></ol>

	</div>
</div>
	</div>
	
</div>
			</div>

			
		</div>

		<div class="main-content-footer">
			<footer class="footer mt-5 py-5 h-auto text-base text-third-text-color relative border-t-2 border-t-border-color">
    <div class="info-container py-3 text-center">
        
        <div class="text-center">
            &copy;
            
              <span>2022</span>
              -
            
            2025&nbsp;&nbsp;<i class="fa-solid fa-heart fa-beat" style="--fa-animation-duration: 0.5s; color: #f54545"></i>&nbsp;&nbsp;<a href="/">xiaoeryu</a>
            
                
                <p class="post-count space-x-0.5">
                    <span>
                        共撰写了 112 篇文章
                    </span>
                    
                </p>
            
        </div>
        
            <script data-swup-reload-script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="relative text-center lg:absolute lg:right-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-right">
                
                    <span id="busuanzi_container_site_uv" class="lg:!block">
                        <span class="text-sm">访问人数</span>
                        <span id="busuanzi_value_site_uv"></span>
                    </span>
                
                
                    <span id="busuanzi_container_site_pv" class="lg:!block">
                        <span class="text-sm">总访问量</span>
                        <span id="busuanzi_value_site_pv"></span>
                    </span>
                
            </div>
        
        <div class="relative text-center lg:absolute lg:left-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-left">
            <span class="lg:block text-sm">由 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="relative top-[2px] inline-block align-baseline" version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1rem" height="1rem" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path fill="#0E83CD" d="M256.4,25.8l-200,115.5L56,371.5l199.6,114.7l200-115.5l0.4-230.2L256.4,25.8z M349,354.6l-18.4,10.7l-18.6-11V275H200v79.6l-18.4,10.7l-18.6-11v-197l18.5-10.6l18.5,10.8V237h112v-79.6l18.5-10.6l18.5,10.8V354.6z"/></svg><a target="_blank" class="text-base" href="https://hexo.io">Hexo</a> 驱动</span>
            <span class="text-sm lg:block">主题&nbsp;<a class="text-base" target="_blank" href="https://github.com/EvanNotFound/hexo-theme-redefine">Redefine v2.8.2</a></span>
        </div>
        
        
            <div>
                博客已运行 <span class="odometer" id="runtime_days" ></span> 天 <span class="odometer" id="runtime_hours"></span> 小时 <span class="odometer" id="runtime_minutes"></span> 分钟 <span class="odometer" id="runtime_seconds"></span> 秒
            </div>
        
        
            <script data-swup-reload-script>
                try {
                    function odometer_init() {
                    const elements = document.querySelectorAll('.odometer');
                    elements.forEach(el => {
                        new Odometer({
                            el,
                            format: '( ddd).dd',
                            duration: 200
                        });
                    });
                    }
                    odometer_init();
                } catch (error) {}
            </script>
        
        
        
    </div>  
</footer>
		</div>
	</div>

	
	<div class="post-tools">
		<div class="post-tools-container">
	<ul class="article-tools-list">
		<!-- TOC aside toggle -->
		
		<li class="right-bottom-tools page-aside-toggle">
			<i class="fa-regular fa-outdent"></i>
		</li>
		

		<!-- go comment -->
		
		<li class="go-comment">
			<i class="fa-regular fa-comments"></i>
		</li>
		
	</ul>
</div>
	</div>
	

	<div class="right-side-tools-container">
		<div class="side-tools-container">
	<ul class="hidden-tools-list">
		<li class="right-bottom-tools tool-font-adjust-plus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-plus"></i>
		</li>

		<li class="right-bottom-tools tool-font-adjust-minus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-minus"></i>
		</li>

		<li class="right-bottom-tools tool-dark-light-toggle flex justify-center items-center">
			<i class="fa-regular fa-moon"></i>
		</li>

		<!-- rss -->
		

		

		<li class="right-bottom-tools tool-scroll-to-bottom flex justify-center items-center">
			<i class="fa-regular fa-arrow-down"></i>
		</li>
	</ul>

	<ul class="visible-tools-list">
		<li class="right-bottom-tools toggle-tools-list flex justify-center items-center">
			<i class="fa-regular fa-cog fa-spin"></i>
		</li>
		
		<li class="right-bottom-tools tool-scroll-to-top flex justify-center items-center">
			<i class="arrow-up fas fa-arrow-up"></i>
			<span class="percent"></span>
		</li>
		
		
	</ul>
</div>
	</div>

	<div class="image-viewer-container">
	<img src="">
</div>

	
	<div class="search-pop-overlay">
	<div class="popup search-popup">
		<div class="search-header">
			<span class="search-input-field-pre">
				<i class="fa-solid fa-keyboard"></i>
			</span>
			<div class="search-input-container">
				<input autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="站内搜索您需要的内容..." spellcheck="false" type="search" class="search-input">
			</div>
			<span class="popup-btn-close">
				<i class="fa-solid fa-times"></i>
			</span>
		</div>
		<div id="search-result">
			<div id="no-result">
				<i class="fa-solid fa-spinner fa-spin-pulse fa-5x fa-fw"></i>
			</div>
		</div>
	</div>
</div>
	

</main>



<script src="/js/build/libs/Swup.min.js"></script>

<script src="/js/build/libs/SwupSlideTheme.min.js"></script>

<script src="/js/build/libs/SwupScriptsPlugin.min.js"></script>

<script src="/js/build/libs/SwupProgressPlugin.min.js"></script>

<script src="/js/build/libs/SwupScrollPlugin.min.js"></script>

<script src="/js/build/libs/SwupPreloadPlugin.min.js"></script>

<script>
    const swup = new Swup({
        plugins: [
            new SwupScriptsPlugin({
                optin: true,
            }),
            new SwupProgressPlugin(),
            new SwupScrollPlugin({
                offset: 80,
            }),
            new SwupSlideTheme({
                mainElement: ".main-content-body",
            }),
            new SwupPreloadPlugin(),
        ],
        containers: ["#swup"],
    });
</script>




	
<script src="/js/build/tools/imageViewer.js" type="module"></script>

<script src="/js/build/utils.js" type="module"></script>

<script src="/js/build/main.js" type="module"></script>

<script src="/js/build/layouts/navbarShrink.js" type="module"></script>

<script src="/js/build/tools/scrollTopBottom.js" type="module"></script>

<script src="/js/build/tools/lightDarkSwitch.js" type="module"></script>

<script src="/js/build/layouts/categoryList.js" type="module"></script>



    
<script src="/js/build/tools/localSearch.js" type="module"></script>




    
<script src="/js/build/tools/codeBlock.js" type="module"></script>




    
<script src="/js/build/layouts/lazyload.js" type="module"></script>




    
<script src="/js/build/tools/runtime.js"></script>

    
<script src="/js/build/libs/odometer.min.js"></script>

    
<link rel="stylesheet" href="/assets/odometer-theme-minimal.css">




  
<script src="/js/build/libs/Typed.min.js"></script>

  
<script src="/js/build/plugins/typed.js" type="module"></script>








    
<script src="/js/build/libs/anime.min.js"></script>





    
<script src="/js/build/tools/tocToggle.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/layouts/toc.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/plugins/tabs.js" type="module" data-swup-reload-script=""></script>




<script src="/js/build/libs/moment-with-locales.min.js" data-swup-reload-script=""></script>


<script src="/js/build/layouts/essays.js" type="module" data-swup-reload-script=""></script>





	
</body>

</html>